package com.feather.tenia.mysql;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.feather.common.data.ColumnCollection;
import com.feather.common.data.simple.SimpleColumn;
import com.feather.tenia.Tenia;
import com.feather.tenia.adapter.ProcedureMetaAdapter;
import com.feather.tenia.adapter.TeniaAdapter;
import com.feather.tenia.adapter.util.CloseUtil;

public class MysqlProcedureMeta extends ProcedureMetaAdapter {
	private static final long	serialVersionUID	= 1L;
	private String				callName;

	@Override
	public String getPrintName() {
		return getCallName();
	}

	@Override
	public String getCallName() {
		if (this.callName == null) {
			StringBuilder builder = new StringBuilder();
			if (getCatalog() != null) {
				builder.append(getCatalog());
				builder.append(".");
				if (getSchema() != null) {
					builder.append(getSchema());
					builder.append(".");
				}
			}
			builder.append("`");
			builder.append(getName());
			builder.append("`");
			this.callName = builder.toString();
		}
		return this.callName;
	}

	@Override
	public void loadColumns(Tenia tenia) throws SQLException {
		ColumnCollection columns = getColumns();

		StringBuilder builder = new StringBuilder();
		builder.append("SELECT * FROM mysql.proc");
		builder.append(" WHERE ");
		if (getCatalog() != null) {
			builder.append(" db=? AND ");
		}
		builder.append(" name=?");

		ResultSet rs = null;
		PreparedStatement statement = null;
		Connection connection = null;
		try {
			connection = tenia.getConnector().getConnection();
			statement = connection.prepareStatement(builder.toString());
			int index = 1;
			if (getCatalog() != null) {
				statement.setString(index++, getCatalog());
			}
			statement.setString(index, getName());

			rs = statement.executeQuery();
			if (rs.next()) {
				String db = rs.getString("db");
				String paramlist = rs.getString("param_list");
				parseParamList(columns, db, paramlist, (TeniaAdapter) tenia);
			}
		} finally {
			CloseUtil.close(rs, statement, connection);
		}
	}

	protected void parseParamList(ColumnCollection columns, String catalog, String paramlist, TeniaAdapter tenia) {
		if (paramlist == null || paramlist.trim().length() == 0) {
			return;
		}
		// IN `inputParam` varchar(255),INOUT `inOutParam` varchar(255)
		String[] parr = paramlist.split(",");
		int sequence = 1;
		for (String p : parr) {
			String[] items = p.split(" ");
			if (items.length != 3) {
				throw new RuntimeException("Invate parameter value by");
			}

			SimpleColumn column = new SimpleColumn();
			column.setCatalog(catalog);

			parseColumnType(column, items[0]);
			parseColumnName(column, items[1]);
			parseParamInfo(column, items[2], tenia);

			column.setOrdinal(sequence++);
			column.setDefault(null);
			column.setNullable(true);
			// column.setRemarks(rs.getString("REMARKS"));

			columns.add(column);
		}
	}

	protected void parseColumnType(SimpleColumn column, String tchars) {
		if (tchars.equalsIgnoreCase("IN")) {
			column.setType((short) DatabaseMetaData.procedureColumnIn);
		} else if (tchars.equalsIgnoreCase("OUT")) {
			column.setType((short) DatabaseMetaData.procedureColumnOut);
		} else if (tchars.equalsIgnoreCase("INOUT")) {
			column.setType((short) DatabaseMetaData.procedureColumnInOut);
		}
	}

	protected void parseColumnName(SimpleColumn column, String nchars) {
		int length = nchars.length();
		if (nchars.charAt(0) == '`' && nchars.charAt(length - 1) == '`') {
			column.setName(nchars.substring(1, length - 1));
		} else {
			column.setName(nchars);
		}
	}

	protected void parseParamInfo(SimpleColumn column, String pchars, TeniaAdapter tenia) {
		String type = null;
		int precision = 0;
		int length = 0;
		short scale = 0;
		short radix = 0;
		if (pchars.endsWith(")")) {
			int at = pchars.indexOf("(");
			type = pchars.substring(0, at);
			length = Integer.parseInt(pchars.substring(at + 1, pchars.length() - 1), 10);
		} else {
			type = pchars;
			length = 1;
		}
		precision = length;
		scale = (short) length;

		column.setDataTypeName(type);
		column.setPrecision(precision);
		column.setLength(length);
		column.setScale(scale);
		column.setRadix(radix);

		tenia.setColumnDataType(column);
	}
}
